package edu.se.jai.websocketgateway.service;

import edu.se.jai.dubboapi.proto.GameServiceProto;
import edu.se.jai.websocketgateway.dto.ConnectData;
import edu.se.jai.websocketgateway.dto.GameRoomDto;
import edu.se.jai.websocketgateway.dto.GameStatus;
import edu.se.jai.websocketgateway.dto.GuessResult;
import edu.se.jai.websocketgateway.dto.MessageType;
import edu.se.jai.websocketgateway.dto.WebSocketMessage;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;

/**
 * 消息发送服务
 *
 * 负责将 Dubbo 返回的 Protobuf DTO 转换为前端可消费的 WebSocket 消息，并完成：
 * - 点对点反馈：发送给特定用户（`/queue/response-user{sessionId}`）
 * - 房间广播：发送给房间内所有玩家（`/room/{roomId}`）
 * - 全局广播：同步房间列表给所有在线玩家（`/topic/roomUpdate`）
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class MessageSendService {

    private final SimpMessagingTemplate messagingTemplate;

    public void notifyConnect(String playerName, String sessionId, boolean success, String info) {
        WebSocketMessage message = new WebSocketMessage();
        message.setType(MessageType.CONNECT_RESPONSE);
        ConnectData responseData = new ConnectData(playerName, sessionId, success, info);
        message.setData(responseData);
        log.info("玩家 {} 连接，{}", playerName, success);
        messagingTemplate.convertAndSend("/queue/response-user" + sessionId, message);
    }

    public void notifyCreate(GameServiceProto.GameRoomDto protoRoom, String sessionId) {
        GameRoomDto room = convertRoom(protoRoom);
        WebSocketMessage message = new WebSocketMessage();
        message.setType(MessageType.ROOM_CREATE);
        message.setData(room);
        String userDestination = "/queue/response-user" + sessionId;
        messagingTemplate.convertAndSend(userDestination, message);
        log.info("发送创建房间响应: sessionId={}, roomId={}", sessionId, room.getRoomId());
        notifyRoomUpdate(room);
    }

    public void notifyJoin(GameServiceProto.GameRoomDto protoRoom, String sessionId) {
        GameRoomDto room = convertRoom(protoRoom);
        WebSocketMessage message = new WebSocketMessage();
        message.setType(MessageType.ROOM_JOIN);
        message.setData(room);
        log.info("玩家 {} 加入房间 {}，当前房间人数: {}", sessionId, room.getRoomId(), room.getPlayers().size());
        String userDestination = "/queue/response-user" + sessionId;
        messagingTemplate.convertAndSend(userDestination, message);
        notifyRoomUpdate(room);
    }

    public void notifyLeave(GameServiceProto.GameRoomDto protoRoom, String sessionId) {
        GameRoomDto room = convertRoom(protoRoom);
        WebSocketMessage message = new WebSocketMessage();
        message.setType(MessageType.ROOM_LEAVE);
        message.setData(room);
        log.info("玩家 {} 离开房间 {}，当前房间人数: {}", sessionId, room.getRoomId(), room.getPlayers().size());
        messagingTemplate.convertAndSend("/room/" + room.getRoomId(), message);
        notifyRoomUpdate(room);
    }

    public void notifyRoomDissolved(GameServiceProto.GameRoomDto protoRoom) {
        GameRoomDto room = convertRoom(protoRoom);
        WebSocketMessage message = new WebSocketMessage();
        message.setType(MessageType.ROOM_DISSOLVE);
        message.setData(room);

        // 广播给所有订阅了房间列表的玩家
        messagingTemplate.convertAndSend("/topic/roomUpdate", message);
        log.info("已广播房间解散通知: {}", room.getRoomId());
    }

    public void notifyRoomUpdate(GameRoomDto room) {
        WebSocketMessage message = new WebSocketMessage();
        message.setType(MessageType.ROOM_UPDATE);
        message.setData(room);
        messagingTemplate.convertAndSend("/room/" + room.getRoomId(), message);
        log.info("已通知房间 {} 更新，当前房间人数: {}", room.getRoomId(), room.getPlayers().size());
        messagingTemplate.convertAndSend("/topic/roomUpdate", message);
        log.info("已广播房间 {} 更新通知，当前房间人数: {}", room.getRoomId(), room.getPlayers().size());
    }

    public void notifyErrorMessage(String sessionId, String errorMessage) {
        WebSocketMessage response = new WebSocketMessage();
        response.setType(MessageType.ERROR);
        response.setData(errorMessage);
        log.info("发送ERROR响应: sessionId={}, content={}", sessionId, errorMessage);
        String userDestination = "/queue/response-user" + sessionId;
        messagingTemplate.convertAndSend(userDestination, response);
        log.info("已发送ERROR响应到用户: {}", sessionId);
    }

    public void notifyAllRooms(List<GameServiceProto.GameRoomDto> protoRooms, String sessionId) {
        List<GameRoomDto> rooms = protoRooms.stream()
                .map(this::convertRoom)
                .collect(Collectors.toList());
        WebSocketMessage response = new WebSocketMessage();
        response.setType(MessageType.ROOMS_LIST);
        response.setData(rooms);
        log.info("发送ALL_ROOMS_LIST响应: sessionId={}, {} 个房间", sessionId, rooms.size());
        String userDestination = "/queue/response-user" + sessionId;
        messagingTemplate.convertAndSend(userDestination, response);
        log.info("已发送ALL_ROOMS_LIST响应到用户: {}", sessionId);
    }

    public void notifyGameStart(GameServiceProto.GameRoomDto protoRoom) {
        GameRoomDto room = convertRoom(protoRoom);
        WebSocketMessage message = new WebSocketMessage();
        message.setType(MessageType.GAME_START);
        message.setData(room);

        // 发送给房间内所有玩家
        messagingTemplate.convertAndSend("/room/" + room.getRoomId(), message);
        log.info("已通知房间 {} 游戏开始", room.getRoomId());

        // 广播房间更新给所有玩家
        notifyRoomUpdate(room);
    }

    public void notifyGameStop(GameServiceProto.GameRoomDto protoRoom) {
        GameRoomDto room = convertRoom(protoRoom);
        WebSocketMessage message = new WebSocketMessage();
        message.setType(MessageType.GAME_STOP);
        message.setData(room);

        // 发送给房间内所有玩家
        messagingTemplate.convertAndSend("/room/" + room.getRoomId(), message);
        log.info("已通知房间 {} 游戏停止", room.getRoomId());

        // 广播房间更新给所有玩家
        notifyRoomUpdate(room);
    }

    public void notifyGuessResult(String roomId, String playerName, Integer guess, Boolean result, String hint, String sessionId) {
        WebSocketMessage personalMessage = new WebSocketMessage();
        personalMessage.setType(MessageType.GUESS_RESULT);
        GuessResult personalResult = GuessResult.createPersonalResult(roomId, playerName, guess, result, hint);
        personalMessage.setData(personalResult);
        messagingTemplate.convertAndSend("/queue/response-user" + sessionId, personalMessage);
        log.info("已发送个人反馈给 {}: {}", playerName, hint);
        
        WebSocketMessage publicMessage = new WebSocketMessage();
        publicMessage.setType(MessageType.GUESS_RESULT);
        GuessResult publicResult = GuessResult.createPublicResult(roomId, playerName, guess, result);
        publicMessage.setData(publicResult);
        messagingTemplate.convertAndSend("/room/" + roomId, publicMessage);
        log.info("已发送公开信息到房间 {}: {}", roomId, publicResult.getMessage());
    }

    private GameRoomDto convertRoom(GameServiceProto.GameRoomDto protoRoom) {
        GameRoomDto dto = new GameRoomDto();
        dto.setRoomId(protoRoom.getRoomId());
        dto.setCreatorName(protoRoom.getCreatorName());
        dto.setPlayers(protoRoom.getPlayersList());
        dto.setStatus(protoRoom.getStatus() == GameServiceProto.GameStatus.PLAYING
                ? GameStatus.PLAYING
                : GameStatus.WAITING);
        return dto;
    }
}

